#include <fstream>
#include "base_util/math_compute.h"
#include "horizon/stream_puller_usb.h"
#include "horizon/stream_pusher.h"
#include "horizon/osd_text.h"

using namespace stream;

int main(int argc, char** argv) {
  int ret = 0;
  LogInfo* log_ifo = new LogInfo(7, "./log", "log"); 

  HBStreamPullerUSB::global_init();
  HBStreamPusher::global_init();
  
  StreamPullerInfo puller_ifo;
  puller_ifo.oriWidth = 1920;
  puller_ifo.oriHeight = 1080;
  puller_ifo.streamAddress = "/dev/video8";
  puller_ifo.transferType = "tcp";
  puller_ifo.enType = AV_CODEC_ID_MJPEG;
  puller_ifo.vdecChn = 0;
  HBStreamPullerUSB *puller = new HBStreamPullerUSB(&puller_ifo, log_ifo);
  if (ret != (puller->init_params()) != 0) {
    spdlog::get("logger")->info("ERROR puller->init_params error ret:{}\n", ret);
    return ret;
  }
  std::thread(&HBStreamPullerUSB::start_pull, puller).detach();


  stream::HBStreamOsdInfo osd_ifo;
  osd_ifo.dstWidth = 1920;
  osd_ifo.dstHeight = 1080;
  osd_ifo.boxThick = 3;
  osd_ifo.boxColorNG = 4;
  osd_ifo.boxColorOK = 3;
  osd_ifo.VpsGrp = 0;
  osd_ifo.vpsChn = CHN_DS0;
  osd_ifo.textColor = FONT_COLOR_CYAN;

  stream::HBOsdText* osder = new stream::HBOsdText(&osd_ifo, log_ifo);
  if (ret != (osder->init_params()) != 0) {
    spdlog::get("logger")->info("ERROR pusher->init_params error ret:{}\n", ret);
    return ret;
  }


  StreamPusherInfo pusher_ifo;
  pusher_ifo.formatName = "flv";
  pusher_ifo.codecProfile = "main";
  pusher_ifo.fps = 25;
  pusher_ifo.bitrate = 4096;        // Mbps
  pusher_ifo.enType = AV_CODEC_ID_H264;
  pusher_ifo.vEncChn = 0;
  // pusher_ifo.streamAddress = "rtmp://192.168.0.10:9935/push/x3";
  pusher_ifo.streamAddress = "rtmp://2.2.2.110:9935/live/livestream";
  pusher_ifo.dstWidth = puller_ifo.oriWidth;
  pusher_ifo.dstHeight = puller_ifo.oriHeight;
  HBStreamPusher *pusher = new HBStreamPusher(&pusher_ifo, log_ifo);
  if (ret != (pusher->init_params()) != 0) {
    spdlog::get("logger")->info("ERROR puller->init_params error ret:{}\n", ret);
    return ret;
  }
  std::thread(&HBStreamPusher::start_push, pusher).detach();


  int x = 100;
  int y = 100;
  int fps_cnt = 0;
  int save_cnt = 0;
  stream::ImageBlob buffer;
  int64_t consume_time = 0;
  int64_t start_time = 0, end_time = 0;
  while(true) {
    std::this_thread::sleep_for(std::chrono::milliseconds(3));
    if (x >= osd_ifo.dstWidth) {x = 100;}
    if (y >= osd_ifo.dstHeight) {y = 100;}

    ret = puller->get_frame(buffer);
    if (ret != 0) { continue; }

    std::cout << "buffer.yuv.size():" << buffer.yuv.size() << std::endl;
    start_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
    std::vector<stream::OSDDrawInfo> osdd_ifos;
    for(int i = 0; i < 9; i++) {
      stream::OSDDrawInfo osdd_ifo;
      // osdd_ifo.texts.push_back("O正确");
      osdd_ifo.texts.push_back("N错误");
      osdd_ifo.x = x + i*150;
      osdd_ifo.y = y;
      osdd_ifo.w = 100;
      osdd_ifo.h = 200;
      osdd_ifos.push_back(osdd_ifo);
    }
    x++;
    y++;
    ret = osder->draw_osd(buffer, osdd_ifos);
    end_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
    consume_time += end_time - start_time;
    if (++fps_cnt % 100 == 0) {
      std::cout << "draw_osd: " << consume_time * 1.0 / fps_cnt << std::endl;
      consume_time = 0;
      fps_cnt = 0;
    }


    if (++save_cnt % 50 == 0) {
      std::ofstream imageyuv("test."+std::to_string(save_cnt)+".yuv", std::ios::binary);
      if(imageyuv.is_open()) {
        imageyuv.write(buffer.yuv.data(), buffer.yuv.size());
        imageyuv.close();
      }
    }
    
    ret = pusher->add_frame(buffer); 

  }
  return 0;
}
